import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import TWEEN from 'three/addons/libs/tween.module.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js';

const rendererList = new Array();

//材质
export const MeshBasicMaterial = 0;
export const MeshPhongMaterial = 1;
export const MeshStandardMaterial = 2;
export const MeshPhysicalMaterial = 3;
export const PointsMaterial = 4;
export const ShaderMaterial = 5;
//颜色空间
export const SRGBColorSpace = THREE.SRGBColorSpace;
export const NoColorSpace = THREE.NoColorSpace;

//混合模式
export const NoBlending = THREE.NoBlending;
export const NormalBlending = THREE.NormalBlending;
export const AdditiveBlending = THREE.AdditiveBlending;
export const SubtractiveBlending = THREE.SubtractiveBlending;
export const MultiplyBlending = THREE.MultiplyBlending;
export const CustomBlending = THREE.CustomBlending;

//返回随机方向三维向量
export function randomVector3(size) {
    return new THREE.Vector3().randomDirection().multiplyScalar(size);
}

//按圆柱坐标返回随机三维向量
export function randomFromCylindricalCoordsVector3(radius, theta, y) {
    return new THREE.Vector3().setFromCylindricalCoords(radius, theta, y);
}

//合并网格
export function mergeGeometry(geometries) {
    return BufferGeometryUtils.mergeGeometries(
        geometries, false);
}
//实例化group
export function instantiateGroup(group) {
    const newGroup = new THREE.Group();
    newGroup.copy(group);
    return newGroup;
}

//创建标签
export function createLabel(words) {
    const ctx = document.createElement('canvas').getContext('2d');
    ctx.font = "100px bolder";
    ctx.canvas.width = ctx.measureText(words[0]).width + 50;
    ctx.canvas.height = 200 * words.length;

    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
    //调整画布后需要重新修改字体
    ctx.font = "100px bolder";
    ctx.textAlign = "center";
    ctx.fillStyle = 'black';
    let y = 150;
    for (const word of words) {
        ctx.fillText(word, ctx.canvas.width / 2, y);
        y += 200;
    }

    const texture = new THREE.CanvasTexture(ctx.canvas);

    const labelMaterial = new THREE.MeshBasicMaterial({
        map: texture,
        side: THREE.DoubleSide,
    });

    const labelGeometry = new THREE.PlaneGeometry(ctx.canvas.width / 200, ctx.canvas.height / 200);
    const label = new THREE.Mesh(labelGeometry, labelMaterial);
    return label;
}

//创建颜色
export function createColor() {
    return new THREE.Color();
}

//创建3D对象
export function createObject3D() {
    return new THREE.Object3D();
}

//根据给定的点数组创建BufferGeometry对象
export function createBufferGeometry(points) {
    return new THREE.BufferGeometry().setFromPoints(points);
}

//创建点
export function createPoints(name, geometry, material) {
    let mesh = new THREE.Points(geometry, material);
    mesh.name = name;
    return mesh;
}

//创建网格
export function createMesh(name, geometry, material) {
    let mesh = new THREE.Mesh(geometry, material);
    mesh.name = name;
    return mesh;
}

//创建球形几何
export function createSphereGeometry(radius,
    widthSegments,
    heightSegments,
    phiStart,
    phiLength,
    thetaStart,
    thetaLength) {
    return new THREE.SphereGeometry(radius,
        widthSegments,
        heightSegments,
        phiStart,
        phiLength,
        thetaStart,
        thetaLength);
}

//创建矩形几何
export function createBoxGeometry(width,
    height,
    depth,
    widthSegments,
    heightSegments,
    depthSegments) {
    return new THREE.BoxGeometry(width,
        height,
        depth,
        widthSegments,
        heightSegments,
        depthSegments);
}

//属性缓存
export function createBufferAttribute(array, itemSize, normalized) {
    return new THREE.BufferAttribute(array, itemSize, normalized);
}

//创建材质
export function createMaterial(params, mtype) {
    let m = null;
    switch (mtype) {
        case MeshBasicMaterial:
            m = new THREE.MeshBasicMaterial(params);
            break;
        case MeshPhongMaterial:
            m = new THREE.MeshPhongMaterial(params);
            break;
        case MeshStandardMaterial:
            m = new THREE.MeshStandardMaterial(params);
            break;
        case MeshPhysicalMaterial:
            m = new THREE.MeshPhysicalMaterial(params);
            break;
        case PointsMaterial:
            m = new THREE.PointsMaterial(params);
            break;
        case ShaderMaterial:
            m = new THREE.ShaderMaterial(params);
            break;
        default:
            break;
    }
    return m;
}

//变换矩阵
export function makeTranslation(x, y, z) {
    return new THREE.Matrix4().makeTranslation(x, y, z);
}

//矩阵取值
export function lerp(x, y, t) {
    return THREE.MathUtils.lerp(x, y, t);
}

//矩阵旋转
export function degToRad(degrees) {
    return THREE.MathUtils.degToRad(degrees);
}

//生成一个指定位置和大小的BOX
export function generateBox(position, size, visible) {
    const geometry = new THREE.BoxGeometry(size.x, size.y, size.z);
    const cube = new THREE.Mesh(geometry);
    cube.translateX(position.x);
    cube.translateY(position.y);
    cube.translateZ(position.z);
    cube.visible = visible;
    return cube;
}

export class TweenManger {
    constructor() {
        this.numTweensRunning = 0;
    }
    _handleComplete() {
        --this.numTweensRunning;
        console.assert(this.numTweensRunning >= 0);
    }
    createTween(targetObject) {
        const self = this;
        ++this.numTweensRunning;
        let userCompleteFn = () => { };
        // 创建一个新的Tween, 并应用我们自己的回调函数
        const tween = new TWEEN.Tween(targetObject).onComplete(function (...args) {
            self._handleComplete();
            userCompleteFn.call(this, ...args);
        });
        // 用我们自己的onComplete代替它的,
        // 因此, 如果用户提供回调, 我们可以调用用户的回调
        tween.onComplete = (fn) => {
            userCompleteFn = fn;
            return tween;
        };
        return tween;
    }
    update() {
        TWEEN.update();
        return this.numTweensRunning > 0;
    }
}

export class SceneParams {
    constructor() {
        //摄像机参数
        this.cameraParams = {
            //视口角度
            fov: 50,
            //近视距离
            near: 0.1,
            //远视距离
            far: 1000,
            //摄像机位置
            position: {
                x: 10,
                y: 5,
                z: 30,
            },
            //朝向
            target: {
                x: 0,
                y: 0,
                z: 0,
            },

        };

        //渲染器参数
        this.rendererParams = {
            //阴影
            shadowenabled: false,
        }

        //定向光源参数
        this.drctLightParams = {
            //颜色
            color: 0x798EAA,
            //强度
            Intensity: 5,
            //阴影
            castShadow: false,
            //光源起点
            position: {
                x: -31,
                y: 17,
                z: 24,
            },
            //光源方向
            TargetPosition: {
                x: -23,
                y: 11,
                z: 22,
            },
            //光源阴影相机范围
            shadowCamera: {
                left: -40,
                right: 40,
                top: 20,
                bottom: -20,
                width: 1024,
                height: 1024,
            },

        }

        //控制器参数
        this.controlsParams = {
            //摄像机平移
            enablePan: true,
            //摄像机的缩放
            enableZoom: true,
            //摄像机旋转
            enableRotate: true,
            //阻尼（惯性）
            enableDamping: false,
            //自动旋转
            autoRotate: false,
            //自动速度
            autoRotateSpeed: 1.0,
            //旋转角度
            angle: {
                //能够水平旋转的角度上限,有效值范围为[-2 * Math.PI，2 * Math.PI]
                maxAzimuthAngle: Infinity,
                //能够水平旋转的角度下限,有效值范围为[-2 * Math.PI，2 * Math.PI]，且旋转角度的上限和下限差值小于2 * Math.PI
                minAzimuthAngle: Infinity,
                //能够垂直旋转的角度的上限，范围是0到Math.PI
                maxPolarAngle: Math.PI,
                //能够垂直旋转的角度的下限，范围是0到Math.PI
                minPolarAngle: 0,
            }
        };

        //后期处理
        this.composerParams = {
            //辉光
            bloom: {
                enabled: false,
                //强度
                strength: 0.2,
                //范围
                radius: 2.0,
                //阈值
                threshold: 0.7,
            }
        }

        //射线参数
        this.raycasterParams = {
            //原点
            origin: new THREE.Vector3(),
            //方向
            direction: new THREE.Vector3(0, 0, - 1),
            //射线距离
            near: 0.1,
            far: 100,
        };
    }
}

export class SceneManager {
    constructor(width = 500, height = 500, shadowEnabled = false) {
        this.width = width;
        this.height = height;
        this.clock = new THREE.Clock(true);
        //纹理贴图映射
        this.txMap = new Map();
        //材质映射
        this.materialMap = new Map();
        //有阴影的物体名称
        this.shadowMap = new Map();
        //被拾取的物体名称
        this.picked = null;
        //被拾取的物体原来的材质
        this.lastPickedMaterial = null;
        //被拾取物体的材质
        this.pickedMaterial = new THREE.MeshStandardMaterial({
            emissive: 0xdc6b1b,
            emissiveIntensity: 0.5,
        });
        //动画序列
        this.clips = new Array();
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(this.width, this.height);
        renderer.shadowMap.enabled = shadowEnabled;

        const sceneInfoList = new Array();
        rendererList.push({ renderer, sceneInfoList });
        this.rendererIndex = rendererList.length - 1;

        this.currentSceneIndex = 0;
        // 对于触屏，不像鼠标总是能有一个位置坐标，
        // 如果用户不在触摸屏幕，我们希望停止拾取操作。
        // 因此，我们选取一个特别的值，表明什么都没选中
        this.pointer = new THREE.Vector2(-100000, -100000);
        this.raycasterEnabled = false;

        //需要释放的资源列表
        this.uncache = new Array();
        this.begin = true;
    }
    addScene(params = new SceneParams(), customEvent = function () { }) {
        const renderer = rendererList[this.rendererIndex].renderer;
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(params.cameraParams.fov, this.width / this.height, params.cameraParams.near, params.cameraParams.far);
        camera.lookAt(new THREE.Vector3(params.cameraParams.target.x, params.cameraParams.target.y, params.cameraParams.target.z));
        camera.updateProjectionMatrix();
        const mixer = new THREE.AnimationMixer(scene);
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.target.set(params.cameraParams.target.x, params.cameraParams.target.y, params.cameraParams.target.z);
        controls.maxAzimuthAngle = params.controlsParams.angle.maxAzimuthAngle;
        controls.minAzimuthAngle = params.controlsParams.angle.minAzimuthAngle;
        controls.maxPolarAngle = params.controlsParams.angle.maxPolarAngle;
        controls.minPolarAngle = params.controlsParams.angle.minPolarAngle;

        const composer = new EffectComposer(renderer);
        const raycaster = new THREE.Raycaster(params.raycasterParams.origin, params.raycasterParams.direction, params.raycasterParams.near, params.raycasterParams.far);//光线投射

        //能够被拾取的物体名称
        const canPickedNameMap = new Map();
        //能够被拾取的物体列表
        const canPickedList = new Array();

        const tweenManager = new TweenManger();

        const sceneInfo = { scene, camera, mixer, controls, composer, raycaster, canPickedNameMap, canPickedList, tweenManager, customEvent };
        rendererList[this.rendererIndex].sceneInfoList.push(sceneInfo);

        const index = rendererList[this.rendererIndex].sceneInfoList.length - 1;
        this._initEnv(index, params);
        return index;
    }

    _getCanvasRelativePosition(event) {
        const renderer = rendererList[this.rendererIndex].renderer;
        const rect = renderer.domElement.getBoundingClientRect();
        return {
            x: (event.clientX - rect.left) * renderer.domElement.width / rect.width,
            y: (event.clientY - rect.top) * renderer.domElement.height / rect.height,
        };
    }

    _setPickPosition(event) {
        // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
        const pos = this._getCanvasRelativePosition(event);
        const renderer = rendererList[this.rendererIndex].renderer;
        this.pointer.x = (pos.x / renderer.domElement.width) * 2 - 1;
        this.pointer.y = (pos.y / renderer.domElement.height) * -2 + 1;
    }

    _clearPickPosition() {
        // 对于触屏，不像鼠标总是能有一个位置坐标，
        // 如果用户不在触摸屏幕，我们希望停止拾取操作。
        // 因此，我们选取一个特别的值，表明什么都没选中
        this.pointer.x = -100000;
        this.pointer.y = -100000;
    }
    //初始化环境
    _initEnv(sceneIndex, params) {
        const controls = rendererList[this.rendererIndex].sceneInfoList[sceneIndex].controls;
        controls.enablePan = params.controlsParams.enablePan;
        controls.enableZoom = params.controlsParams.enableZoom;
        controls.enableDamping = params.controlsParams.enableDamping;
        controls.enableRotate = params.controlsParams.enableRotate;
        controls.autoRotate = params.controlsParams.autoRotate;
        controls.autoRotateSpeed = params.controlsParams.autoRotateSpeed;

        const camera = rendererList[this.rendererIndex].sceneInfoList[sceneIndex].camera;
        camera.position.set(params.cameraParams.position.x, params.cameraParams.position.y, params.cameraParams.position.z);
        //每次调整相机位置更新控制器
        controls.update();

        const scene = rendererList[this.rendererIndex].sceneInfoList[sceneIndex].scene;
        //定向光源
        const directionalLight = new THREE.DirectionalLight(params.drctLightParams.color, params.drctLightParams.Intensity);
        scene.add(directionalLight);
        directionalLight.castShadow = params.drctLightParams.castShadow;
        //设置位置
        directionalLight.position.set(params.drctLightParams.position.x, params.drctLightParams.position.y, params.drctLightParams.position.z);
        //设置方向
        directionalLight.target.position.set(params.drctLightParams.TargetPosition.x, params.drctLightParams.TargetPosition.y, params.drctLightParams.TargetPosition.z);
        scene.add(directionalLight.target);
        //调整光源阴影相机
        directionalLight.shadow.camera.left = params.drctLightParams.shadowCamera.left;
        directionalLight.shadow.camera.right = params.drctLightParams.shadowCamera.right;
        directionalLight.shadow.camera.top = params.drctLightParams.shadowCamera.top;
        directionalLight.shadow.camera.bottom = params.drctLightParams.shadowCamera.bottom;
        directionalLight.shadow.mapSize.width = params.drctLightParams.shadowCamera.width;
        directionalLight.shadow.mapSize.height = params.drctLightParams.shadowCamera.height;
        //更新摄像机投影矩阵
        directionalLight.shadow.camera.updateProjectionMatrix();

        const composer = rendererList[this.rendererIndex].sceneInfoList[sceneIndex].composer;
        composer.addPass(new RenderPass(scene, camera));
        //设置辉光
        if (params.composerParams.bloom.enabled) {
            const bloomPass = new UnrealBloomPass(new THREE.Vector2(256, 256), params.composerParams.bloom.strength, params.composerParams.bloom.radius, params.composerParams.bloom.threshold);
            composer.addPass(bloomPass);
        }
    }

    //获取画布dom元素
    getRenderDom() {
        return rendererList[this.rendererIndex].renderer.domElement;
    }

    //获取TweenManger
    getTweenManger() {
        return rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].tweenManager;
    }
    //开启自动旋转
    enableAutoRotate() {
        const controls = rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].controls;
        if (controls) {
            controls.autoRotate = true;
        }
    }

    //禁用自动旋转
    disableAutoRotate() {
        const controls = rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].controls;
        if (controls) {
            controls.autoRotate = false;
        }
    }

    //设置指定场景环境贴图
    setEnv(index, envName) {
        if (!this.txMap.has(envName)) {
            console.warn("没有环境贴图");
            return;
        }
        const envTX = this.txMap.get(envName);
        envTX.mapping = THREE.EquirectangularReflectionMapping;

        const scene = rendererList[this.rendererIndex].sceneInfoList[index].scene;
        //设为背景
        scene.background = envTX;
        //设为场景中所有物体的环境贴图
        scene.environment = envTX;
    }

    //加载贴图
    loadHDRAndTX(hdrs, paths, onLoad, onProgress, onError) {
        const manager = new THREE.LoadingManager();
        manager.onProgress = onProgress;
        manager.onError = onError;
        manager.onLoad = onLoad;

        //加载环境贴图
        const hdrloader = new RGBELoader(manager);
        for (const hdr of hdrs) {
            this.txMap.set(hdr, hdrloader.load(hdr));
        }
        //加载纹理贴图
        const TXloader = new THREE.TextureLoader(manager);
        for (const path of paths) {
            this.txMap.set(path, TXloader.load(path));
        }
    }

    //创建环境贴图
    createHDR(name, buffer, onLoad, onError) {
        const hdrloader = new RGBELoader();
        const texture = new THREE.DataTexture();
        let texData;
        try {
            texData = hdrloader.parse(buffer);
        } catch (error) {
            if (onError !== undefined) {
                onError(error);
            } else {
                console.error(error);
                return;
            }
        }

        if (texData.image !== undefined) {

            texture.image = texData.image;

        } else if (texData.data !== undefined) {

            texture.image.width = texData.width;
            texture.image.height = texData.height;
            texture.image.data = texData.data;

        }

        texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : THREE.ClampToEdgeWrapping;
        texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : THREE.ClampToEdgeWrapping;

        texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : THREE.LinearFilter;
        texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : THREE.LinearFilter;

        texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;

        if (texData.colorSpace !== undefined) {
            texture.colorSpace = texData.colorSpace;
        } else if (texData.encoding !== undefined) { // @deprecated, r152
            texture.encoding = texData.encoding;
        }

        if (texData.flipY !== undefined) {
            texture.flipY = texData.flipY;
        }

        if (texData.format !== undefined) {
            texture.format = texData.format;
        }

        if (texData.type !== undefined) {
            texture.type = texData.type;
        }

        if (texData.mipmaps !== undefined) {
            texture.mipmaps = texData.mipmaps;
            texture.minFilter = THREE.LinearMipmapLinearFilter; // presumably...
        }

        if (texData.mipmapCount === 1) {
            texture.minFilter = THREE.LinearFilter;
        }

        if (texData.generateMipmaps !== undefined) {
            texture.generateMipmaps = texData.generateMipmaps;
        }
        texture.needsUpdate = true;

        switch (texture.type) {
            case THREE.FloatType:
            case THREE.HalfFloatType:
                texture.colorSpace = THREE.LinearSRGBColorSpace;
                texture.minFilter = THREE.LinearFilter;
                texture.magFilter = THREE.LinearFilter;
                texture.generateMipmaps = false;
                texture.flipY = true;
                break;
        }
        this.txMap.set(name, texture);
        if (onLoad) onLoad(texture, texData);
    }

    //添加材质
    addMaterial(name, params, mtype) {
        switch (mtype) {
            case MeshBasicMaterial:
                this.materialMap.set(name, new THREE.MeshBasicMaterial(params));
                break;
            case MeshPhongMaterial:
                this.materialMap.set(name, new THREE.MeshPhongMaterial(params));
                break;
            case MeshStandardMaterial:
                this.materialMap.set(name, new THREE.MeshStandardMaterial(params));
                break;
            case MeshPhysicalMaterial:
                this.materialMap.set(name, new THREE.MeshPhysicalMaterial(params));
                break;
            default:
                break;
        }
    }

    //在开始绘制前设置指定场景可拾取物体,能够被拾取的物体名称映射,key=名称，value=是否改变材质
    setCanPickedMap(index, pickedMap) {
        rendererList[this.rendererIndex].sceneInfoList[index].canPickedNameMap = pickedMap;
    }

    //在开始绘制前设置有阴影的物体
    setShadowList(shadowList) {
        for (const item of shadowList) {
            this.shadowMap.set(item, item);
        }
    }

    //通过URL加载模型
    loadModelByURL(pathAndLoadFuns, onLoad, onProgress, onError) {
        const manager = new THREE.LoadingManager();
        manager.onProgress = onProgress;
        manager.onError = onError;
        manager.onLoad = onLoad;
        const loader = new GLTFLoader(manager);
        const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath("/draco/");
        loader.setDRACOLoader(dracoLoader);
        for (const pf of pathAndLoadFuns) {
            loader.load(pf.path, pf.func, undefined, undefined);
        }
    }

    //直接加载模型数据
    loadModelByData(data, onLoad, onError) {
        const loader = new GLTFLoader();
        const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath("/draco/");
        loader.setDRACOLoader(dracoLoader);
        loader.parse(data, "/", onLoad, onError);
    }

    //给模型上材质
    addMaterialForModel(model) {
        if (model.isMesh) {
            if (this.materialMap.has(model.name)) {
                model.material = this.materialMap.get(model.name);
            }
            //blender导出的材质这两个参数会导致摩尔纹
            model.material.normalScale = new THREE.Vector2(1, 1);
            model.material.side = THREE.FrontSide;
        } if (model.isObject3D) {
            for (const item of model.children) {
                this.addMaterialForModel(item);
            }
        }
    }

    //处理阴影和拾取
    _dealModel(index, model) {
        const sceneInfo = rendererList[this.rendererIndex].sceneInfoList[index];
        if (model.isMesh) {
            if (this.shadowMap.has(model.name)) {
                model.castShadow = true;
                model.receiveShadow = true;
            }
            if (sceneInfo.canPickedNameMap.has(model.name)) {
                sceneInfo.canPickedList.push(model);
            }
        }
        if (model.isObject3D) {
            if (sceneInfo.canPickedNameMap.has(model.name)) {
                sceneInfo.canPickedList.push(model);
            }
            for (const item of model.children) {
                this._dealModel(index, item);
            }
        }
    }

    //指定场景添加能够拾取的物体
    addCanPicked(index, model, name, changeColor = true) {
        const sceneInfo = rendererList[this.rendererIndex].sceneInfoList[index];
        sceneInfo.canPickedList.push(model);
        sceneInfo.canPickedNameMap.set(name, changeColor);
    }

    //指定场景删除能够拾取的物体
    deleteCanPicked(sceneIndex, name) {
        const sceneInfo = rendererList[this.rendererIndex].sceneInfoList[sceneIndex];
        sceneInfo.canPickedNameMap.delete(name);
        let index = 0;
        let has = false;
        for (const item of sceneInfo.canPickedList) {
            if (item.name === name) {
                has = true;
                break;
            }
            index++;
        }
        if (has) {
            sceneInfo.canPickedList.splice(index, 1);
        }
    }

    //修改指定场景模型材质
    changeModelMaterial(index, modelName, materialName) {
        const model = rendererList[this.rendererIndex].sceneInfoList[index].scene.getObjectByName(modelName);
        if (model && this.materialMap.has(materialName)) {
            model.material = this.materialMap.get(materialName);
        } else {
            console.warn("缺少模型或材质");
        }
    }

    //将模型加入指定场景
    addModelToScene(index, model) {
        this._dealModel(index, model);
        rendererList[this.rendererIndex].sceneInfoList[index].scene.add(model);
    }

    //查询当前场景物体
    findObjectByName(name) {
        return rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].scene.getObjectByName(name);
    }

    //添加动画
    addAnimationToScene(animation) {
        this.clips.push(animation);
    }

    //当前场景播放动画
    playAnimation(animationName, root, timeScale = 1.0, loop = false) {
        const clip = THREE.AnimationClip.findByName(this.clips, animationName);
        const mixer = rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].mixer;
        let action = mixer.existingAction(clip, root);
        if (!action) {
            action = mixer.clipAction(clip, root);
        }
        action = action.reset();
        if (!loop) {
            action = action.setLoop(THREE.LoopOnce);
        }
        action.timeScale = timeScale;
        action.play();
    }

    //当前场景淡入动画
    crossFadeToAnimation(lastActionName, newActionName, root, timeScale = 1.0, loop = false) {
        let clip = THREE.AnimationClip.findByName(this.clips, lastActionName);
        const mixer = rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].mixer;
        let action = mixer.existingAction(clip, root);
        if (!action) {
            clip = THREE.AnimationClip.findByName(this.clips, newActionName);
            action = mixer.clipAction(clip, root);
            if (!loop) {
                action = action.setLoop(THREE.LoopOnce);
            }
            action.timeScale = timeScale;
            action.play();
        } else {
            clip = THREE.AnimationClip.findByName(this.clips, newActionName);
            let newAction = mixer.existingAction(clip, root);
            if (!newAction) {
                newAction = mixer.clipAction(clip, root);
            }
            newAction = newAction.reset();
            if (!loop) {
                newAction = newAction.setLoop(THREE.LoopOnce);
            }
            newAction.timeScale = timeScale;
            action.crossFadeTo(newAction, 0.2, true).reset().play();
        }

    }


    //注册动画循环结束事件和全部动作的结束事件
    registeAnimationFinishEvent(loopEvent, finishedEvent) {
        for (const sceneInfo of rendererList[this.rendererIndex].sceneInfoList) {
            const mixer = sceneInfo.mixer;

            if (loopEvent) {
                mixer.addEventListener('loop', loopEvent);
            }
            if (finishedEvent) {
                mixer.addEventListener('finished', finishedEvent);
            }
        }
    }

    //切换场景
    changeSceneInfo(index) {
        this.currentSceneIndex = index;
    }

    //开始绘制场景
    start(timestamp) {
        if (!this.begin) {
            return;
        }
        if (!rendererList[this.rendererIndex]) {
            return;
        }
        const sceneInfo = rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex];
        if (sceneInfo) {
            if (sceneInfo.customEvent) {
                sceneInfo.customEvent();
            }
            if (this.raycasterEnabled) {
                this._picked();
            }
            const tweenManager = sceneInfo.tweenManager;
            tweenManager.update();
            const composer = sceneInfo.composer;
            composer.render();
            const controls = sceneInfo.controls;
            controls.update();
            while (this.uncache.length > 0) {
                let t = this.uncache.shift();
                this._release(t);
            }

            const mixer = sceneInfo.mixer;
            mixer.update(this.clock.getDelta());
        }
        requestAnimationFrame(this.start.bind(this));
    }

    //获取总运行时长
    getElapsedTime() {
        return this.clock.getElapsedTime();
    }

    //获取每帧运行时长
    getDelta() {
        return this.clock.getDelta();
    }

    //开启射线选择
    enableRaycaster() {
        this.raycasterEnabled = true;
        const renderer = rendererList[this.rendererIndex].renderer;
        renderer.domElement.addEventListener('mousemove', this._setPickPosition.bind(this));
        renderer.domElement.addEventListener('mouseout', this._clearPickPosition.bind(this));
        renderer.domElement.addEventListener('mouseleave', this._clearPickPosition.bind(this));
    }

    //关闭射线选择
    disableRaycaster() {
        this.raycasterEnabled = false;
        const renderer = rendererList[this.rendererIndex].renderer;
        renderer.domElement.removeEventListener('mousemove', this._setPickPosition.bind(this));
        renderer.domElement.removeEventListener('mouseout', this._clearPickPosition.bind(this));
        renderer.domElement.removeEventListener('mouseleave', this._clearPickPosition.bind(this));
    }

    //获取鼠标选中对象
    getPicked() {
        return this.picked;
    }

    _picked() {
        // 恢复上一个被拾取对象的材质
        if (this.picked) {
            this.picked.material = this.lastPickedMaterial;
            this.picked = undefined;
        }

        // 通过摄像机和鼠标位置更新射线
        const raycaster = rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].raycaster;
        const camera = rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].camera;
        raycaster.setFromCamera(this.pointer, camera);

        // 计算物体和射线的焦点
        const intersects = raycaster.intersectObjects(rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].canPickedList, false);
        if (intersects.length) {
            // 找到第一个对象，它是离鼠标最近的对象
            let first = intersects[0].object;
            this.picked = first;
            // 保存它原来的材质
            this.lastPickedMaterial = this.picked.material;
            // 设置它的材质
            if (rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex].canPickedNameMap.get(this.picked.name)) {
                this.picked.material = this.pickedMaterial;
            }
        }
    }

    _disposeMesh(mesh) {
        if (mesh.geometry) {
            mesh.geometry.dispose();
        }
        if (mesh.material) {
            mesh.material.dispose();
        }
        if (mesh.skeleton) {
            mesh.skeleton.dispose();
        }
        //贴图也许还在使用所以单独处理
    }

    _release(model) {
        if (model.isObject3D) {
            //释放根对象的所有内存资源
            for (const sceneInfo of rendererList[this.rendererIndex].sceneInfoList) {
                sceneInfo.mixer.uncacheRoot(model);
            }

            model.removeFromParent();
            for (const item of model.children) {
                this._release(item);
            }
        }

        if (model.isTexture || model.isMaterial || model.isBufferGeometry) {
            model.dispose();
        }

        if (model.isMesh) {
            //销毁几何数据和材质
            this._disposeMesh(model);
        }
    }

    //更新尺寸
    resize(width, height) {
        this.width = width;
        this.height = height;
        // 更新相机参数
        const sceneInfo = rendererList[this.rendererIndex].sceneInfoList[this.currentSceneIndex];
        sceneInfo.camera.aspect = this.width / this.height;
        sceneInfo.camera.updateProjectionMatrix();
        // 更新渲染尺寸
        rendererList[this.rendererIndex].renderer.setSize(this.width, this.height);
        sceneInfo.composer.render();
    }
    //释放资源
    release(target) {
        this.uncache.push(target);
    }

    //销毁场景，实际内存并不是立即释放
    destroy() {
        this.begin = false;
        if (this.raycasterEnabled) {
            this.disableRaycaster();
        }

        //释放几何数据和材质
        for (const item of rendererList[this.rendererIndex].sceneInfoList) {
            this._release(item.scene);
            item.controls.dispose();
        }
        //释放纹理贴图
        for (const item of this.txMap.values()) {
            item.dispose();
        }
        rendererList[this.rendererIndex].renderer.dispose();
        rendererList[this.rendererIndex] = null;
    }
}
